package response

import (
	stdhttp "net/http"

	"github.com/go-kratos/kratos/v2/errors"
	"github.com/go-kratos/kratos/v2/transport/http"
)

type resp struct {
	Code     int               `json:"code"`
	Msg      string            `json:"msg"`
	Data     interface{}       `json:"data,omitempty"`
	Metadata map[string]string `json:"metadata,omitempty"`
}

func success(data interface{}) *resp {
	return &resp{
		Code: 0,
		Msg:  "ok",
		Data: data,
	}
}

func failed(code int, msg string, metadata map[string]string) *resp {
	return &resp{
		Code:     code,
		Msg:      msg,
		Metadata: metadata,
	}
}

func ResponseEncoder(w stdhttp.ResponseWriter, r *stdhttp.Request, v interface{}) error {
	if v != nil {
		if rd, ok := v.(http.Redirector); ok {
			url, code := rd.Redirect()
			stdhttp.Redirect(w, r, url, code)
			return nil
		}
	}
	resp := success(v)
	codec, _ := http.CodecForRequest(r, "Accept")
	data, err := codec.Marshal(resp)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "application/"+codec.Name()) //application/
	_, err = w.Write(data)
	if err != nil {
		return err
	}
	return nil
}

func ErrorEncoder(errReasons map[string]int32) http.EncodeErrorFunc {
	return func(w stdhttp.ResponseWriter, r *stdhttp.Request, err error) {
		se := errors.FromError(err)
		resp := failed(int(errReasons[se.Reason]), se.Message, se.Metadata)
		codec, _ := http.CodecForRequest(r, "Accept")
		body, err := codec.Marshal(resp)
		if err != nil {
			w.WriteHeader(stdhttp.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/"+codec.Name())
		w.WriteHeader(int(se.Code))
		_, _ = w.Write(body)
	}
}
